package com.koron.plan.web.repairplan.service.impl;

import com.alibaba.fastjson.JSON;
import com.koron.bean.workflow.RedirectQuery;
import com.koron.common.core.business.workflow.bean.po.SysWorkflow;
import com.koron.common.core.business.workflow.service.SysWorkflowService;
import com.koron.common.core.util.CodeTools;
import com.koron.common.core.util.OrgCacheUtils;
import com.koron.plan.config.Constants;
import com.koron.plan.web.common.CommonUtils;
import com.koron.plan.web.repairplan.bean.convertor.PlanDeptConvertor;
import com.koron.plan.web.repairplan.bean.convertor.PlanPackageIssueConvertor;
import com.koron.plan.web.repairplan.bean.entity.PlanPackageEquipmentBean;
import com.koron.plan.web.repairplan.bean.query.PlanPackageQuery;
import com.koron.plan.web.repairplan.bean.vo.*;
import com.koron.plan.web.repairplan.mapper.PlanPackageMapper;
import com.koron.plan.web.repairplan.notified.RepairPlanNotifyHolder;
import com.koron.plan.web.repairplan.service.PlanPackageDeptService;
import com.koron.plan.web.repairplan.service.PlanPackageEquipmentService;
import com.koron.plan.web.repairplan.service.PlanPackageIssueService;
import com.koron.plan.web.repairplan.service.PlanPackageService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.koron.ebs.mybatis.SessionFactory;
import org.koron.ebs.mybatis.TaskAnnotation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author twcao
 * @title: PlanPackageServiceImpl
 * @projectName GDH_EAM_V2
 * @description: 检修计划包service实现
 * @date 2021/9/1310:19
 */
@Slf4j
@Service
public class PlanPackageServiceImpl implements PlanPackageService {

    @Autowired
    private PlanDeptConvertor deptConvertor;

    @Autowired
    private PlanPackageIssueConvertor issueConvertor;

    @Autowired
    private PlanPackageDeptService deptService;

    @Autowired
    private PlanPackageIssueService issueService;

    @Autowired
    private PlanPackageEquipmentService equipmentService;

    @Autowired
    private RepairPlanNotifyHolder notifyHolder;

    @Autowired
    private OrgCacheUtils orgCacheUtils;

    @Autowired
    private SysWorkflowService sysWorkflowService;

    @Autowired
    private PlanPackageIssueService planPackageIssueService;

    /**
     * 根据计划包获取详情
     * @param factory 会话
     * @param packageId 计划包id
     * @return
     */
    @Override
    @TaskAnnotation("queryById")
    public PlanPackageVO queryById(SessionFactory factory, String packageId) {
        PlanPackageMapper packageMapper = factory.getMapper(PlanPackageMapper.class);
        PlanPackageVO planPackageVO = packageMapper.queryById(packageId);
        planPackageVO.getDepts().stream().flatMap(row -> row.getIssues().stream()).forEach(row -> {
            // 设备管理单位名称
            row.setDeptManageName(orgCacheUtils.getOrgNameById(row.getDeptManage()));
            // 主办单位
            row.setOrganizerName(orgCacheUtils.getOrgNameById(row.getOrganizer()));
        });
        return planPackageVO;
    }

    /**
     * 根据检修计划包统计
     * @param factory   会话
     * @param packageId 检修计划报id
     * @param deptId 部门id
     * @return
     */
    @Override
    @TaskAnnotation("statById")
    public PackageStatVO statById(SessionFactory factory, String packageId, String deptId) {
        PlanPackageMapper packageMapper = factory.getMapper(PlanPackageMapper.class);
        List<Map<String, BigDecimal>> maps = packageMapper.statById(packageId, deptId);
        Map<String, IssueState> organizers = new HashMap<>();
        IssueState overall = new IssueState();
        maps.stream().forEach(row -> {
            IssueState organizer = new IssueState()
                    .setToIssue(row.get(Constants.REPAIR_PACKAGE_ISSUE_STATE.TO_ISSUE + "").intValue())
                    .setIssued(row.get(Constants.REPAIR_PACKAGE_ISSUE_STATE.ISSUED + "").intValue())
                    .setExecute(row.get(Constants.REPAIR_PACKAGE_ISSUE_STATE.EXECUTE + "").intValue())
                    .setFinish(row.get(Constants.REPAIR_PACKAGE_ISSUE_STATE.FINISH + "").intValue());
            overall.setToIssue(overall.getToIssue() + organizer.getToIssue());
            overall.setIssued(overall.getIssued() + organizer.getIssued());
            overall.setExecute(overall.getExecute() + organizer.getExecute());
            overall.setFinish(overall.getFinish() + organizer.getFinish());
            organizers.put(row.get(Constants.DEPT_NAME_KEY) + "", organizer);
        });
        // 统计
        return PackageStatVO.builder().overall(overall).organizers(organizers).build();
    }

    /**
     * 检修计划包分页查询
     *
     * @param factory 会话
     * @param query    查询条件
     * @return 符合条件的集合
     */
    @Override
    @TaskAnnotation("queryList")
    public List<PlanPackageVO> queryList(SessionFactory factory, PlanPackageQuery query) {
        PlanPackageMapper packageMapper = factory.getMapper(PlanPackageMapper.class);
        return packageMapper.queryList(query);
    }

    /**
     * 新增或修改
     * @param factory 会话
     * @param vo 实体
     * @return 返回保存后的实体
     */
    @Override
    @TaskAnnotation("saveOrUpdate")
    public PlanPackageVO saveOrUpdate(SessionFactory factory, PlanPackageVO vo) {
        PlanPackageMapper packageMapper = factory.getMapper(PlanPackageMapper.class);
        // 校验（合法性判断）
        // 初始值（主键、创建/修改人、时间）
        notifyHolder.initializeBefore(factory, vo);
        vo.setId(StringUtils.isBlank(vo.getId()) ? CodeTools.getCode32() : vo.getId());
        // 设置编号
        vo.setCode(StringUtils.isBlank(vo.getCode()) ? CommonUtils.getCodeNo(Constants.REPAIR_PACKAGE_PREFIX, 3) : vo.getCode());
        CommonUtils.sorted(vo.getDepts());
        vo.getDepts().stream().forEach(dept -> {
            CommonUtils.update(dept, vo.getUpdateBy(), vo.getUpdateByName());
            dept.setId(StringUtils.isBlank(dept.getId()) ? CodeTools.getCode32() : dept.getId());
            dept.setPackageId(vo.getId());
            List<PlanPackageIssueVO> issues = dept.getIssues();
            CommonUtils.sorted(issues);
            issues.stream().forEach(issue -> {
                CommonUtils.update(issue, vo.getUpdateBy(), vo.getUpdateByName());
                issue.setId(StringUtils.isBlank(issue.getId()) ? CodeTools.getCode32() : issue.getId());
                issue.setPlanCode(StringUtils.isBlank(issue.getIssueCode()) ? CommonUtils.getCodeNo(Constants.ISSUE_JOB_TYPE.prefixMap.get(issue.getJobType()), 3) : issue.getIssueCode());
                issue.setPackageId(vo.getId());
                issue.setPackageDeptId(dept.getId());
                // 如果检修计划是由检修计划包生成的，则将检修计划包的创建人所在单位设置为责任单位（而不是检修计划包的创建人所在单位）
                issue.setOrgId(dept.getDeptId());
                List<PlanPackageEquipmentBean> equipments = issue.getEquipments();
                CommonUtils.sorted(equipments);
                equipments.stream().forEach(equipment -> {
                    equipment.setId(StringUtils.isBlank(equipment.getId()) ? CodeTools.getCode32() : equipment.getId());
                    equipment.setPackageId(vo.getId());
                    equipment.setPackageDeptId(dept.getId());
                    equipment.setPackageIssueId(issue.getId());
                    equipment.setCreateTime(new Date());
                });
            });
        });
        vo.setStatus(vo.getStatus() == null ? Constants.REPAIR_PACKAGE_STATE.DRAFT : vo.getStatus());
        notifyHolder.saveBefore(factory, vo);
        // 保存检修计划包主体
        packageMapper.saveOrUpdate(vo);
        // 主办单位
        List<PlanPackageDeptVO> depts = vo.getDepts();
        deptService.deleteByPackageId(factory, vo.getId());
        deptService.saveOrUpdate(factory, deptConvertor.vosToBeans(depts));
        // 工单计划列表
        List<PlanPackageIssueVO> issueVOs = depts.stream().flatMap(dept -> dept.getIssues().stream()).collect(Collectors.toList());
        issueService.deleteByPackageId(factory, vo.getId());
        issueService.saveOrUpdate(factory, issueConvertor.vosToBeans(issueVOs));
        // 工单计划设备
        List<PlanPackageEquipmentBean> equipments = issueVOs.stream().flatMap(issueVO -> issueVO.getEquipments().stream()).collect(Collectors.toList());
        equipmentService.deleteByPackageId(factory, vo.getId());
        equipmentService.saveOrUpdate(factory, equipments);
        notifyHolder.saveAfter(factory, vo);
        return queryById(factory, vo.getId());
    }

    /**
     * 删除检修计划包
     * @param factory   会话
     * @param packageId 计划包id
     * @return 删除的检修计划包
     */
    @Override
    @TaskAnnotation("deleteById")
    public PlanPackageVO deleteById(SessionFactory factory, String packageId) {
        PlanPackageVO vo = queryById(factory, packageId);
        Assert.isTrue(Constants.REPAIR_PACKAGE_STATE.DRAFT.equals(vo.getStatus()), "非草稿状态的检修计划包不支持删除");
        notifyHolder.deleteBefore(factory, vo);
        PlanPackageMapper packageMapper = factory.getMapper(PlanPackageMapper.class);
        // 1、检修计划包主体
        packageMapper.deleteById(packageId);
        // 2、主办单位
        deptService.deleteByPackageId(factory, packageId);
        // 3、计划设备
        equipmentService.deleteByPackageId(factory, packageId);
        notifyHolder.deleteAfter(factory, vo);
        // 4、工单计划（含工单的工作流）
        issueService.deleteByPackageId(factory, packageId);
        // 5、删除计划包的工作流
        sysWorkflowService.deleteByDataId(packageId);
        return vo;
    }

    /**
     * 更新检修计划检修包工作流状态
     * @param factory
     * @param packageId
     * @return
     */
    @Override
    @TaskAnnotation("updateState")
    public Boolean updateState(SessionFactory factory, String packageId) {
        return null;
    }

    /**
     * 工作流更新
     *
     * @param factory
     * @param redirectQuery
     */
    @Override
    @TaskAnnotation("workflowUpdate")
    public Boolean workflowUpdate(SessionFactory factory, RedirectQuery redirectQuery) {
        Integer operation = redirectQuery.getOperation();
        PlanPackageVO vo = JSON.parseObject(redirectQuery.getFormVariables(), PlanPackageVO.class);
        switch (operation) {
            case 256: // 撤回
            case 1: // 驳回
                // 驳回的节点编号
                // 驳回到草稿节点
                vo.setStatus(Constants.REPAIR_PACKAGE_STATE.DRAFT);
                saveOrUpdate(factory, vo);
                break;
            case 32: // 同意
                vo.setStatus(Constants.REPAIR_PACKAGE_STATE.TO_AUDIT);
                saveOrUpdate(factory, vo);
        }
        return true;
    }

    /**
     * 工作流完结
     *
     * @param factory
     * @param redirectQuery
     * @return
     */
    @Override
    @TaskAnnotation("updateEnd")
    public Boolean updateEnd(SessionFactory factory, RedirectQuery redirectQuery) {
        PlanPackageVO vo = JSON.parseObject(redirectQuery.getFormVariables(), PlanPackageVO.class);
        // 审核完成到执行中
        vo.setStatus(Constants.REPAIR_PACKAGE_STATE.EXECUTION);
        // 1、修改检修计划包的状态
        saveOrUpdate(factory, vo);
        List<PlanPackageIssueVO> issues = vo.getDepts().stream().flatMap(row -> row.getIssues().stream()).collect(Collectors.toList());
        // 2、将检修计划包的工作流，复制给所有计划包内的计划
        issues.stream().forEach(issue -> {
            // 1、更新工作流状态
            // 状态修改为下发
            issue.setStatus(Constants.REPAIR_PACKAGE_ISSUE_STATE.ISSUED);
            issue.setStatus(0);
            issueService.saveOrUpdate(factory, issue);
            planPackageIssueService.issued(factory,issue.getId());
            log.info("检修计划包生成检修计划： {}", JSON.toJSONString(issue));
            // 2、 复制工作流（该检修计划包内的所有计划，与计划包共用一个工作流）
            SysWorkflow workflow = new SysWorkflow();
            workflow.setDataId(vo.getId());
            List<SysWorkflow> sysWorkflows = sysWorkflowService.queryAll(workflow);
            Assert.isTrue(CollectionUtils.size(sysWorkflows) > 0, "检修计划包工作流不存在");
            // 同一个billId对应多个dataId，即同一个工作流对应多个业务单
            SysWorkflow sysWorkflow = sysWorkflows.get(0);
            sysWorkflow.setDataId(issue.getId());
            sysWorkflow.setModuleCode(null);
            sysWorkflowService.insert(sysWorkflow);
        });
        return true;
    }
}
